
local FamilyMonsterExcel = require("excel.FamilyMonster")
local ArgConf = FamilyMonsterExcel.arg[1]
local MonsterConf = FamilyMonsterExcel.monster
local SkillConf = FamilyMonsterExcel.skill
local ItemConf = FamilyMonsterExcel.item
local PKConf = FamilyMonsterExcel.pk
local Msg = require("core.Msg")
local FamilyManager = require("family.FamilyManager")
local FamilyLogicFW = require("family.FamilyLogicFW")
local Broadcast = require("broadcast.Broadcast")
local SkillNotify = require("skill.Notify")
local Lang = require("common.Lang")
local ObjHuman = require("core.ObjHuman")
local BagLogic = require("bag.BagLogic")
local Grid = require("bag.Grid")
local GridLogic = require("bag.GridLogic")
local FamilyDefine = require("family.FamilyDefine")
local HtmlUtil = require("common.HtmlUtil")
local Buffer = require("buffer.Buffer")
local RoleUIControl = require("role.RoleUIControl")
local ExcelLevelReward = require("excel.LevelReward")
local MailHandler = require("mail.Handler")
local ItemDefine = require("bag.ItemDefine")
local Util = require("common.Util")
local ExcelMap = require("excel.Map")
local RoleAttr = require("role.RoleAttr")
local Copy = require("copy.CopyL")
local CopyHandler = require("copy.Handler")
local ObjMonster = require("core.ObjMonster")
local ShopHelp = require("shop.ShopHelp")
local ShopHandler = require("shop.Handler")
local ExcelLevelReward = require("excel.LevelReward")
local CopyFamily = require("copy.CopyFamily")
local string = _G.string
local math = _G.math
local time = _G.time
local table = _G.table

local function getSkillID(key, value)

    local nextLvConf = nil
    for _, conf in ipairs(SkillConf) do
        if conf.key == key then
            nextLvConf = SkillConf[conf.nextLvID]
            if nextLvConf then
                if value >= conf.startValue and value < nextLvConf.startValue then
                    skillID = conf.skillID
                    study = 1
                    lv = conf.lv
                    break
                elseif value < conf.startValue then
                    skillID = conf.skillID
                    study = 0
                    lv = conf.lv
                    break
                end
            else
                skillID = conf.skillID
                study = 1
                lv = conf.lv
                break
            end
        end
    end

    return skillID, study, lv
end

-- ȡ�������޵ȼ�
function getFamilyMonsterLv(family)

    if not family then
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return
    end

    if not family.monster then
        return 1
    end

    return family.monster.lv

end

function CG_FAMILY_MONSTER_PEIYANG_QUERY(human)
    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NO_FAMILY)
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_FAMILY_LV_NOT_ENOUGH, ArgConf.needFamilyLv))
        return
    end

    if not family.monster then
        family.monster = {}
        FamilyManager.update(family)
    end

    if not family.monster.lv then
        family.monster.lv = 1
        FamilyManager.update(family)
    end

    if not family.monster.attrs then
        family.monster.attrs = {}
        FamilyManager.update(family)
    end

    local monster = family.monster
    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PEIYANG_QUERY
    msgRet.monsterLv = monster.lv or 1
    msgRet.zhandouli = getZhandouli(human, true)
    msgRet.qinmi = human.db.familyMonsterQinmi or 0
    msgRet.attrRate = ArgConf.getAttrRate(msgRet.qinmi)
    msgRet.exp = monster.exp or 0
    msgRet.expMax = MonsterConf[msgRet.monsterLv].exp
    msgRet.source = MonsterConf[msgRet.monsterLv].source

    msgRet.comonCnt =  ArgConf.commonDailyCnt - (human.db.familyMonsterCommonCnt or 0)
    msgRet.highLvCnt = ArgConf.highLvDailyCnt - (human.db.familyMonsterHighLvCnt or 0)

    -- monster attrs
    msgRet.monsterAttrs[0] = 0
    msgRet.skills[0] = 0
    local msgMonsterAttr = nil
    local msgMonsterAttrMax = nil
    local msgSkill = nil
    local skillID, skillStudy, skillLv
    for _, attr in ipairs(MonsterConf[msgRet.monsterLv].attrs) do

        -- current value
        msgRet.monsterAttrs[0] = msgRet.monsterAttrs[0] + 1
        msgMonsterAttr = msgRet.monsterAttrs[msgRet.monsterAttrs[0]]
        msgMonsterAttr.key = attr.key
        msgMonsterAttr.value = attr.value + (monster.attrs[attr.key] or 0)

        -- skill
        msgRet.skills[0] = msgRet.skills[0] + 1
        msgSkill = msgRet.skills[msgRet.skills[0]]
        skillID, skillStudy, skillLv = getSkillID(msgMonsterAttr.key, msgMonsterAttr.value)
        SkillNotify.setSkillData(human, skillID, msgSkill)
        msgSkill.isActivation = skillStudy
        msgSkill.level = skillLv
    end
    Msg.send(msgRet, human.fd)
end

function CG_FAMILY_MONSTER_PEIYANG_CONF_QUERY(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return
    end

    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PEIYANG_CONF_QUERY
    msgRet.commonYinliang = ArgConf.commonYinliang
    msgRet.commonExp = ArgConf.commonExp
    msgRet.commonQinmi = ArgConf.commonQinmi
    msgRet.commonRoleExp = ExcelLevelReward[ArgConf.commonRoleExpID][human.db.lv].exp
    msgRet.highLvYuanbao = ArgConf.highLvYuanbao
    msgRet.highLvExp = ArgConf.highLvExp
    msgRet.highLvQinmi = ArgConf.highLvQinmi
    msgRet.highLvRoleExp = ExcelLevelReward[ArgConf.highLvRoleExpID][human.db.lv].exp
    msgRet.specialRoleExp = ExcelLevelReward[ArgConf.specialRoleExpID][human.db.lv].exp

    msgRet.monsterAttrsMax[0] = 0
    for _, attr in ipairs(MonsterConf[#MonsterConf].attrs) do
        msgRet.monsterAttrsMax[0] = msgRet.monsterAttrsMax[0] + 1
        msgMonsterAttrMax = msgRet.monsterAttrsMax[msgRet.monsterAttrsMax[0]]
        msgMonsterAttrMax.key = attr.key
        msgMonsterAttrMax.value = attr.value + key2MaxValue[attr.key]
    end
    Msg.send(msgRet, human.fd)

end

local function wrapperPetyangLogItem(msgLog, data)
    msgLog.time = data.time
    msgLog.name = data.name or ""
    msgLog.uuid = data.uuid or ""
    msgLog.type = data.type

    local exp, qinmi = 0, 0
    if data.type == FamilyDefine.FAMILY_MONSTER_LOG_TYPE1 then
        exp = ArgConf.commonExp
        qinmi = ArgConf.commonQinmi
    elseif data.type == FamilyDefine.FAMILY_MONSTER_LOG_TYPE2 then
        exp = ArgConf.highLvExp
        qinmi = ArgConf.highLvQinmi
    elseif data.type == FamilyDefine.FAMILY_MONSTER_LOG_TYPE3 then
        qinmi = data.qinmi
    end

    msgLog.exp = exp
    msgLog.qinmi = qinmi

    msgLog.attrs[0] = 0
    if data.type == FamilyDefine.FAMILY_MONSTER_LOG_TYPE3 then
        for key, value in pairs(data.attrs) do
            msgLog.attrs[0] = msgLog.attrs[0] + 1
            msgLog.attrs[msgLog.attrs[0]].key = key
            msgLog.attrs[msgLog.attrs[0]].value = value
        end
    end

end

function CG_FAMILY_MONSTER_PEIYANG_LOG(human)
    if not isOpen() then
        return
    end
    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return
    end

    if not family.monster then
        family.monster = {}
        FamilyManager.update(family)
    end

    if not family.monster.logs then
        family.monster.logs = {}
        FamilyManager.update(family)
    end

    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PEIYANG_LOG
    msgRet.logs[0] = 0

    for _, data in ipairs(family.monster.logs) do
        msgRet.logs[0] = msgRet.logs[0] + 1
        wrapperPetyangLogItem(msgRet.logs[msgRet.logs[0]], data)
    end
    Msg.send(msgRet, human.fd)
end

function checkLvUp(family, human)
    if not family.monster then
        assert()
    end

    if not family.monster.lv then
        family.monster.lv = 1
    end

    if family.monster.lv >= #MonsterConf then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_MAX_LV)
        return 0
    end

    local maxLv = ArgConf.getMonsterMaxLv(family.familyLv)
    if family.monster.lv + 1 > maxLv and family.monster.exp >= MonsterConf[family.monster.lv].exp then					-- to do
        family.monster.exp = MonsterConf[family.monster.lv].exp
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NEED_FAMILY_LV)
        return 0
    end

    local levelUp = 0
    while family.monster.exp > 0 do
        local needExp = MonsterConf[family.monster.lv].exp
        if needExp <= family.monster.exp then
            levelUp = 1
            family.monster.exp = family.monster.exp - needExp
            family.monster.lv = family.monster.lv + 1
            if family.monster.lv >=  #MonsterConf then
                family.monster.exp = 0
                break
            end
        else
            break
        end
    end

    return levelUp
end

function GC_FAMILY_MONSTER_PEIYANG_ADD_LOG(family, log)
    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PEIYANG_ADD_LOG
    wrapperPetyangLogItem(msgRet.log, log)
    Msg.sendMulti(msgRet, FamilyManager.getOnlineFds(family))
end

local function addLog(family, log)
    if not family.monster.logs then
        family.monster.logs = {}
    end

    table.insert(family.monster.logs, 1, log)
    if #family.monster.logs > ArgConf.logCnt then
        family.monster.logs[#family.monster.logs] = nil
    end
end

function addCommonLog(human, family)
    local log = {}
    log.time = os.time()
    log.name = human.db.name
    log.uuid = human.db._id
    log.type = FamilyDefine.FAMILY_MONSTER_LOG_TYPE1
    addLog(family, log)
    GC_FAMILY_MONSTER_PEIYANG_ADD_LOG(family, log)
end

function addHighLvLog(human, family)
    local log = {}
    log.time = os.time()
    log.name = human.db.name
    log.uuid = human.db._id
    log.type = FamilyDefine.FAMILY_MONSTER_LOG_TYPE2
    addLog(family, log)
    GC_FAMILY_MONSTER_PEIYANG_ADD_LOG(family, log)
end

function addSpecialLog(human, family, tmpAttrs, qinmi)
    local log = {}
    log.time = os.time()
    log.name = human.db.name
    log.uuid = human.db._id
    log.type = FamilyDefine.FAMILY_MONSTER_LOG_TYPE3
    log.qinmi = qinmi
    local attrs = {}
    Util.copyTable(tmpAttrs, attrs)
    log.attrs = attrs
    addLog(family, log)
    GC_FAMILY_MONSTER_PEIYANG_ADD_LOG(family, log)
end

function addLvupLog(family)
    local log = {}
    log.time = os.time()
    log.type = FamilyDefine.FAMILY_MONSTER_LOG_TYPE4
    addLog(family, log)
    GC_FAMILY_MONSTER_PEIYANG_ADD_LOG(family, log)
end

function GC_FAMILY_MONSTER_PEIYANG_CHANGE(family)
    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PEIYANG_CHANGE
    FamilyManager.sendFamily(msgRet, family)
end

function CG_FAMILY_MONSTER_COMMON_PEIYANG(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NO_FAMILY)
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_FAMILY_LV_NOT_ENOUGH, ArgConf.needFamilyLv))
        return
    end

    if not family.monster then
        family.monster = {}
        FamilyManager.update(family)
    end

    ObjHuman.updateDaily(human)
    if human.db.familyMonsterCommonCnt and human.db.familyMonsterCommonCnt >= ArgConf.commonDailyCnt then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_OVER_COMMON_CNT)
        return
    end

    if ObjHuman.getYinliang(human, "yinliang") < ArgConf.commonYinliang then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_YINLIANG_NOT_ENOUGH)
        return
    end

    ObjHuman.decYinliang(human, "yinliang", -ArgConf.commonYinliang, "family_monster")

    if not human.db.familyMonsterCommonCnt then
        human.db.familyMonsterCommonCnt = 0
    end
    human.db.familyMonsterCommonCnt = human.db.familyMonsterCommonCnt + 1

    if not family.monster.exp then
        family.monster.exp = 0
    end

    family.monster.exp = family.monster.exp + ArgConf.commonExp
    local lvup = checkLvUp(family, human)
    FamilyManager.update(family)

    if not human.db.familyMonsterQinmi then
        human.db.familyMonsterQinmi = 0
    end

    human.db.familyMonsterQinmi = human.db.familyMonsterQinmi + ArgConf.commonQinmi

    local expConf = ExcelLevelReward[ArgConf.commonRoleExpID]
    ObjHuman.addExp(human, expConf[human.db.lv].exp)

    GC_FAMILY_MONSTER_PEIYANG_CHANGE(family)
    Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PEIYANG_OK)
    Broadcast.sendBroadcast(human, Lang.MOUSE, HtmlUtil.string.format(Lang.FAMILY_MONSTER_PEIYANG_ADD_EXP_OK, ArgConf.commonExp))

    -- add log
    if lvup == 1 then
        addLvupLog(family)
        -- calc family member attr
        reCalcFamilyMemberAttr(family)
    else
        -- calc human attr
        ObjHuman.doCalc(human)
    end

    addCommonLog(human, family)

end

function CG_FAMILY_MONSTER_HIGH_LV_PEIYANG(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NO_FAMILY)
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_FAMILY_LV_NOT_ENOUGH, ArgConf.needFamilyLv))
        return
    end

    if not family.monster then
        family.monster = {}
        FamilyManager.update(family)
    end

    ObjHuman.updateDaily(human)
    if human.db.familyMonsterHighLvCnt and human.db.familyMonsterHighLvCnt >= ArgConf.highLvDailyCnt then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_OVER_HIGH_LV_CNT)
        return
    end

    if human.db.yuanbao < ArgConf.highLvYuanbao then
        ShopHelp.onNoRMB(human)
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_YUANBAO_NOT_ENOUGH)
        return
    end

    ObjHuman.updateYuanbao(human, -ArgConf.highLvYuanbao, "family_monster")

    if not human.db.familyMonsterHighLvCnt then
        human.db.familyMonsterHighLvCnt = 0
    end
    human.db.familyMonsterHighLvCnt = human.db.familyMonsterHighLvCnt + 1

    if not family.monster.exp then
        family.monster.exp = 0
    end

    family.monster.exp = family.monster.exp + ArgConf.highLvExp
    local lvup = checkLvUp(family, human)
    FamilyManager.update(family)

    if not human.db.familyMonsterQinmi then
        human.db.familyMonsterQinmi = 0
    end

    human.db.familyMonsterQinmi = human.db.familyMonsterQinmi + ArgConf.highLvQinmi

    local expConf = ExcelLevelReward[ArgConf.highLvRoleExpID]
    ObjHuman.addExp(human, expConf[human.db.lv].exp)

    GC_FAMILY_MONSTER_PEIYANG_CHANGE(family)
    Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PEIYANG_OK)
    Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_PEIYANG_ADD_EXP_OK, ArgConf.highLvExp))

    -- add log
    if lvup == 1 then
        addLvupLog(family)
        -- calc family member attr
        reCalcFamilyMemberAttr(family)
    else
        -- calc human attr
        ObjHuman.doCalc(human)
    end

    addHighLvLog(human, family)

end

-- ���¼�������Ա����
function reCalcFamilyMemberAttr(family)
    for k, v in ipairs(family.memberList) do
        local human = ObjHuman.onlineUuid[v.uuid]
        if human and human.fd then
            ObjHuman.doCalc(human)
        end
    end
end

tmpAttrs = tmpAttrs or {}
function CG_FAMILY_MONSTER_SPECIAL_PEIYANG(human, id)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NO_FAMILY)
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_FAMILY_LV_NOT_ENOUGH, ArgConf.needFamilyLv))
        return
    end

    if not family.monster then
        family.monster = {}
    end

    local itemConf = nil
    for _, conf in ipairs(ItemConf) do
        if conf.itemID == id then
            itemConf = conf
            break
        end
    end

    if not itemConf then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_ITEM_ID_INVALID)
        return
    end

    local itemCnt = BagLogic.getItemCount(human, id)
    if itemCnt < 1 then
        ShopHandler.showQuickBuy(human, id, 1)
        return
    end
    BagLogic.delItemsById(human, id, 1, "family_monster")

    if not family.monster.attrs then
        family.monster.attrs = {}
    end

    -- clear attrs
    for key, _ in pairs(tmpAttrs) do
        tmpAttrs[key] = nil
    end

    -- add value
    for key, values in pairs(itemConf.values) do
        local value = math.random(values[1], values[2])
        family.monster.attrs[key] = (family.monster.attrs[key] or 0) + value
        tmpAttrs[key] = value
    end

    -- check max value
    for key, value in pairs(family.monster.attrs) do
        if value > key2MaxValue[key] then
            family.monster.attrs[key] = key2MaxValue[key]
        end
    end
    FamilyManager.update(family)

    if not human.db.familyMonsterQinmi then
        human.db.familyMonsterQinmi = 0
    end

    human.db.familyMonsterQinmi = human.db.familyMonsterQinmi + itemConf.qinmi

    local expConf = ExcelLevelReward[ArgConf.specialRoleExpID]
    ObjHuman.addExp(human, expConf[human.db.lv].exp)

    GC_FAMILY_MONSTER_PEIYANG_CHANGE(family)
    Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PEIYANG_OK)

    reCalcFamilyMemberAttr(family)

    addSpecialLog(human, family, tmpAttrs, itemConf.qinmi)

end

local function wrapperPkItem(msgItem, conf)
    msgItem.id = conf.id
    msgItem.name = conf.name
    msgItem.needFamilyYinliang = conf.needFamilyYinliang
    msgItem.needMonsterLv = conf.needMonsterLv
    msgItem.expMax = conf.exp
    GridLogic.makeGrids(conf.showGrids, msgItem.itemDatas)
    msgItem.desc = conf.desc
end

function CG_FAMILY_MONSTER_PK_CONF_QUERY(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NO_FAMILY)
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_FAMILY_LV_NOT_ENOUGH, ArgConf.needFamilyLv))
        return
    end

    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PK_CONF_QUERY
    GridLogic.makeItem(ArgConf.pkItemGrid, msgRet.itemData)
    msgRet.lists[0] = 0

    for _, conf in ipairs(PKConf) do
        msgRet.lists[0] = msgRet.lists[0] +1
        wrapperPkItem(msgRet.lists[msgRet.lists[0]], conf)
    end
    Msg.send(msgRet, human.fd)

end

function CG_FAMILY_MONSTER_PK_INFO_QUERY(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NO_FAMILY)
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_FAMILY_LV_NOT_ENOUGH, ArgConf.needFamilyLv))
        return
    end

    if not family.monster then
        family.monster = {}
    end

    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PK_INFO_QUERY
    msgRet.id = family.monster.pkID or 1
    msgRet.exp =  family.monster.pkExp or 0
    Msg.send(msgRet, human.fd)

end

function sendGC_FAMILY_MONSTER_PK_INFO_QUERY_2_FAMILY(family)
    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PK_INFO_QUERY
    msgRet.id = family.monster.pkID or 1
    msgRet.exp =  family.monster.pkExp or 0
    FamilyManager.sendFamily(msgRet, family)
end

function checkPkLvUp(family)
    if not family.monster then
        assert()
    end

    if not family.monster.pkID then
        family.monster.pkID = 1
    end

    if family.monster.pkID >= #PKConf then
        return 0
    end

    local levelUp = 0
    while family.monster.pkExp > 0 do
        local needExp = PKConf[family.monster.pkID].exp
        if needExp <= family.monster.pkExp then
            levelUp = 1
            family.monster.pkExp = family.monster.pkExp - needExp
            family.monster.pkID = family.monster.pkID + 1
            if family.monster.pkID>= #PKConf then
                family.monster.pkExp = 0
                break
            end
        else
            break
        end
    end
    return levelUp
end

function CG_FAMILY_MONSTER_PK_ADD_EXP(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NO_FAMILY)
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_FAMILY_LV_NOT_ENOUGH, ArgConf.needFamilyLv))
        return
    end

    local itemCnt = BagLogic.getItemCount(human, ArgConf.pkItemID)
    if itemCnt < 1 then
        ShopHandler.showQuickBuy(human, ArgConf.pkItemID, 1, CG_FAMILY_MONSTER_PK_ADD_EXP)
        return
    end

    if not family.monster then
        family.monster = {}
    end

    if not family.monster.pkID then
        family.monster.pkID = 1
    end

    local conf = PKConf[family.monster.pkID]
    if conf.nextLvID == 0 then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PK_MAX_LV)
        return
    end

    if not family.monster.lv then
        family.monster.lv = 1
    end

    if family.monster.lv < conf.needMonsterLv then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_LV_NOT_ENOUGH, conf.needMonsterLv))
        return
    end

    BagLogic.delItemsById(human, ArgConf.pkItemID, 1, "family_monster")

    if not family.monster.pkExp then
        family.monster.pkExp = 0
    end

    family.monster.pkExp = family.monster.pkExp + ArgConf.pkItemAddExp
    local lvup = checkPkLvUp(family)
    FamilyManager.update(family)

    sendGC_FAMILY_MONSTER_PK_INFO_QUERY_2_FAMILY(family)
    Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PK_ADD_EXP_OK)

    if lvup == 1 then
        Broadcast.sendBroadcastFDs(FamilyManager.getOnlineFds(family), Lang.FAMILY,
        string.format(Lang.FAMILY_MONSTER_PK_LV_OK, PKConf[family.monster.pkID].name)
        )
    end

end

function CG_FAMILY_MONSTER_PK_START(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return
    end

    local fds = FamilyManager.getOnlineFds(family)
    if fds[0] < ArgConf.pkOpenRoleCnt then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_PK_ONLINE_ROLE_CNT, ArgConf.pkOpenRoleCnt))
        return
    end

    if not family.monster then
        return
    end

    if not family.monster.pkID then
        return
    end

    local leftTime = getLeftTime(human)
    if leftTime ~= 0 then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PK_ING)
        return
    end

    if family.monster.pkStartID then
        local conf = PKConf[family.monster.pkStartID]
        local copyInfo = CopyFamily.getCopyInfoByFamilyUuid(human.db.familyUuid, conf.copyID)
        if copyInfo then
            Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NOT_CLEAR)
            return
        end
    end

    local member = FamilyManager.getMember(family, human.db._id)
    if not (member.official == FamilyDefine.OFFICIAL_LEADER) then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_NOT_LEADER)
        return
    end

    local conf = PKConf[family.monster.pkID]
    if conf.copyID == 0 then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PK_LV_NOT_ENOUGH)
        return
    end

    if family.familyMoney < conf.needFamilyYinliang then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_FAMILY_YINLIANG_NOT_ENOUGH)
        return
    end

    FamilyLogicFW.updateFamilyMoney(family, -conf.needFamilyYinliang)

    family.monster.pkStartTime = os.time() + ArgConf.waitTime
    family.monster.pkStartID = conf.id
    family.monster.pkID = 1
    family.monster.pkExp = 0
    FamilyManager.update(family)

    familyUuid2FinishFlag[human.db.familyUuid] = nil

    -- refresh icons
    for k, v in ipairs(family.memberList) do
        local target = ObjHuman.onlineUuid[v.uuid]
        if target and target.fd then
            RoleUIControl.sendLine1FnIcon(target)
        end
    end

    sendGC_FAMILY_MONSTER_PK_INFO_QUERY_2_FAMILY(family)

    if member.official == FamilyDefine.OFFICIAL_LEADER then
        local mm = Msg.gc.GC_BROADCAST
        mm.type = Lang.UP + Lang.FAMILY
        mm.msg = string.format(Lang.FAMILY_MONSTER_PK_START_OK1, HtmlUtil.fontName(human.db.name, human.db._id), math.ceil(ArgConf.waitTime / 60))
        FamilyManager.sendFamily(mm, family)
    elseif member.official == FamilyDefine.OFFICIAL_FU_LEADER then
        local mm = Msg.gc.GC_BROADCAST
        mm.type = Lang.UP + Lang.FAMILY
        mm.msg = string.format(Lang.FAMILY_MONSTER_PK_START_OK2, HtmlUtil.fontName(human.db.name, human.db._id), math.ceil(ArgConf.waitTime / 60))
        FamilyManager.sendFamily(mm, family)
    end

end

function CG_FAMILY_MONSTER_PK_ENTER_CONF_QUERY(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return
    end

    if not family.monster then
        return
    end

    if not family.monster.pkStartID then
        return
    end

    local leftTime = getLeftTime(human)
    if leftTime == 0 then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PK_NOT_START)
        return
    end

    local msgRet = Msg.gc.GC_FAMILY_MONSTER_PK_ENTER_CONF_QUERY
    wrapperPkItem(msgRet.item, PKConf[family.monster.pkStartID])
    Msg.send(msgRet, human.fd)

end


mailGrids = mailGrids or {}
function CG_FAMILY_MONSTER_PK_ENTER(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return
    end

    if not family.monster then
        return
    end

    local now = os.time()
    if now < family.monster.pkStartTime then
        Broadcast.sendBroadcast(human, Lang.MOUSE, string.format(Lang.FAMILY_MONSTER_PK_NO_ENTER, math.ceil((family.monster.pkStartTime - now)/60)))
        return
    end

    if now > family.monster.pkStartTime + getCopyTime(human) then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PK_NOT_START)
        return
    end

    if human.db.familyPkStartTime == family.monster.pkStartTime then
        Broadcast.sendBroadcast(human, Lang.MOUSE, Lang.FAMILY_MONSTER_PK_JOIN_AGAIN)
        return
    end

    human.db.familyPkStartTime = family.monster.pkStartTime
    local conf = PKConf[family.monster.pkStartID]
    CopyHandler.copyEnter(human, conf.copyID)

    mailGrids[1] = conf.mailGrid
    MailHandler.addSystemMessage(human.db._id, string.format(Lang.FAMILY_MONSTER_PK_TITLE1, conf.name), Lang.FAMILY_MONSTER_PK_CONTENT1, mailGrids)

end

-- ��ս����ʣ��ʱ��
function getLeftTime(human)

    if not isOpen() then
        return 0
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return 0
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return 0
    end

    if not family.monster then
        return 0
    end

    if not family.monster.pkStartTime then
        return 0
    end

    if familyUuid2FinishFlag[human.db.familyUuid] then
        return 0
    end

    local copyTime = getCopyTime(human)
    if copyTime == 0 then
        return 0
    end

    local now = os.time()
    local startTime = family.monster.pkStartTime
    if now < startTime then
        return startTime - now
    elseif now + 10 >= startTime + copyTime then	-- ��ǰ10�����
        return 0
    else
        return now - startTime - copyTime
    end

end

-- ��ս���޸���ʱ��
function getCopyTime(human)

    if not isOpen() then
        return 0
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return 0
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return 0
    end

    if not family.monster then
        return 0
    end

    if not family.monster.pkStartID then
        return 0
    end

    local conf = PKConf[family.monster.pkStartID]
    return ExcelMap.copy[conf.copyID].time

end

-- add monster
familyUuid2FinishFlag = familyUuid2FinishFlag or {}
function onRoomBegin(copyID, roomID)

    local familyUuid = Copy.roomDatas[copyID][roomID].familyUuid
    local family = FamilyManager.findByUuid(familyUuid)
    local conf = PKConf[family.monster.pkStartID]
    local monster = ObjMonster.create(conf.monsterID)
    local mapList = Copy.copyList[copyID][roomID]
    local cnt = family.monster.lv
    for mapID, sceneID in pairs(mapList) do
        ObjMonster.enterScene(monster, sceneID, conf.bornX, conf.bornY)
        for _, id in ipairs(conf.buffIDs) do
            Buffer.add(id, monster, monster)
            Buffer.addBufCount(monster, id, cnt)
        end
        break
    end

end

function onRoomFinish(copyID, roomID)

    local familyUuid = Copy.roomDatas[copyID][roomID].familyUuid
    familyUuid2FinishFlag[familyUuid] = true
    local family = FamilyManager.findByUuid(familyUuid)

    -- refresh icons
    for k, v in ipairs(family.memberList) do
        local target = ObjHuman.onlineUuid[v.uuid]
        if target and target.fd then
            RoleUIControl.sendLine1FnIcon(target)
        end
    end

end

-- ���
function onZhengDian()

    if not isOpen() then
        return
    end

    for uuid, family in pairs(FamilyManager.uuid2Family) do

        if family.familyLv >= ArgConf.needFamilyLv then

            if not family.monster then
                family.monster = {}
            end

            if not family.monster.lv then
                family.monster.lv = 1
            end

            if not family.monster.pkID then
                family.monster.pkID = 1
            end

            local conf = PKConf[family.monster.pkID]
            if conf.nextLvID ~= 0 and family.monster.lv >= conf.needMonsterLv then
                if not family.monster.pkExp then
                    family.monster.pkExp = 0
                end
                family.monster.pkExp = family.monster.pkExp + ArgConf.pkExpPerHour
                local lvup = checkPkLvUp(family)
                FamilyManager.update(family)
                sendGC_FAMILY_MONSTER_PK_INFO_QUERY_2_FAMILY(family)

                if lvup == 1 then
                    Broadcast.sendBroadcastFDs(FamilyManager.getOnlineFds(family), Lang.FAMILY,
                    string.format(Lang.FAMILY_MONSTER_PK_LV_OK, PKConf[family.monster.pkID].name)
                    )
                end

            end

        end
    end

end

-- ���Լ���
function doCalc(human)

    if not isOpen() then
        return
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return
    end

    if family.familyLv < ArgConf.needFamilyLv then
        return
    end

    if not family.monster then
        family.monster = {}
        FamilyManager.update(family)
    end

    local lv = family.monster.lv or 1
    if not family.monster.attrs then
        family.monster.attrs = {}
        FamilyManager.update(family)
    end

    local rate = ArgConf.getAttrRate(human.db.familyMonsterQinmi or 0)
    for _, attr in ipairs(MonsterConf[lv].attrs) do
        human.attr[attr.key] = human.attr[attr.key] + (attr.value + (family.monster.attrs[attr.key] or 0)) * rate
    end

end

function getZhandouli(human, monster)

    if not isOpen() then
        return 0
    end

    local family = FamilyManager.findByUuid(human.db.familyUuid)
    if not family then
        return 0
    end

    if not family.monster then
        return 0
    end

    if not family.monster.lv then
        return 0
    end

    local mConf = MonsterConf[family.monster.lv]

    local score = 0
    if monster then
        for _, attr in ipairs(mConf.attrs) do
            score = score + RoleAttr.getScore(attr.key) * attr.value
        end

        if family.monster.attrs then
            for key, value in pairs(family.monster.attrs) do
                score = score + RoleAttr.getScore(key) * value
            end
        end
    else
        if family.monster.attrs then
            local rate = ArgConf.getAttrRate(human.db.familyMonsterQinmi or 0)
            for _, attr in ipairs(MonsterConf[family.monster.lv].attrs) do
                score = score + (attr.value + (family.monster.attrs[attr.key] or 0)) * rate
            end
        end
    end

    return score
end

function isOpen()
    return true
end

function onTimerTenSec(copyID, roomID)
    local fuuid = Copy.roomDatas[copyID][roomID].familyUuid
    local humanList = Copy.getCopyHumanList(copyID, roomID)
    for _, human in ipairs(humanList) do
        if human.db.familyUuid ~= fuuid then
            CopyHandler.CG_COPY_LEAVE(human)
            RoleUIControl.sendLine1FnIcon(human)
        end
    end
end

key2MaxValue = nil
function init()
    if not isOpen() then
        return
    end
    ArgConf.getMonsterMaxLv = load(ArgConf.getMonsterMaxLvFn)()
    ArgConf.getAttrRate = load(ArgConf.getAttrRateFn)()
    ArgConf.pkItemGrid = Grid.create(ArgConf.pkItemID, 1)

    for _, conf in ipairs(PKConf) do
        conf.showGrids = {}
        for index, show in ipairs(conf.shows) do
            conf.showGrids[index] = Grid.create(show[1], show[2], show[3])
        end
        if conf.mailItemID ~= 0 then
            conf.mailGrid = Grid.create(conf.mailItemID, 1, 1)
        end
    end

    key2MaxValue = {}
    for _, conf in ipairs(ItemConf) do
        if conf.key ~= 0 then
            key2MaxValue[conf.key] = conf.maxValue
        end
    end

end
